home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / sample code / quicktime / quicktimeintro / play movie w.controller / common files / macframework.c < prev    next >
Encoding:
Text File  |  2000-10-06  |  24.0 KB  |  905 lines

  1. //////////
  2. //
  3. //    File:        MacFramework.c
  4. //
  5. //    Contains:    Code for the QuickTime sample code framework that is specific to the Macintosh. 
  6. //                This code handles windows, menus, events, and other low-level things. Put your
  7. //                application-specific code into the file ComApplication.c. 
  8. //
  9. //    Written by:    Tim Monroe
  10. //                Based on the QTShell code written by Tim Monroe, which in turn was based on the MovieShell
  11. //                code written by Apple DTS (Kent Sandvik). This current version is now very far removed from
  12. //                MovieShell.
  13. //
  14. //    Copyright:    © 1999 by Apple Computer, Inc., all rights reserved.
  15. //
  16. //    Change History (most recent first):
  17. //
  18. //       <10>         03/02/00    rtm        made changes to get things running under CarbonLib
  19. //       <9>         01/14/00    rtm        reworked window-dragging and -updating code to support graphics files
  20. //       <8>         12/23/99    rtm        tweaked mouseDown handling in QTFrame_StandardModalDialogEventFilter
  21. //       <7>         12/16/99    rtm        added gMouseClickTime global variable and code to set it in mouseUp
  22. //                                    case in QTFrame_HandleEvent
  23. //       <6>         12/12/99    rtm        tweaked inDrag handling in QTFrame_HandleEvent
  24. //       <5>         11/30/99    rtm        option-click in close box now closes all open movie windows (per HIG)
  25. //       <4>         11/29/99    rtm        reworked QTFrame_DestroyMovieWindow to use NavAskSaveChanges
  26. //       <3>         11/16/99    rtm        factored QTFrame_HandleEvent out of QTFrame_MainEventLoop, so we can
  27. //                                    handle events from other code, if necessary
  28. //       <2>         11/11/99    rtm        made some preliminary changes for Carbon; still some work to be done
  29. //       <1>         11/05/99    rtm        first file; based on earlier sample code
  30. //       
  31. //////////
  32.  
  33. //////////
  34. //
  35. // header files
  36. //
  37. //////////
  38.  
  39. #include "MacFramework.h"
  40.  
  41.  
  42. //////////
  43. //
  44. // global variables
  45. //
  46. //////////
  47.  
  48. Boolean             gShuttingDown = false;                // are we shutting down?
  49. Boolean                gAppInForeground;                    // is our application in the foreground?    
  50. Boolean                gHasNewDialogCalls;                    // are the new Dialog Manager functions available?
  51.  
  52. Str255                 gWindowTitle = kDefaultWindowTitle;    // default name for created windows
  53. Rect                 gWindowRect = kDefaultWindowRect;    // default rectangle for created windows
  54. GrowZoneUPP            gAppGrowZoneUPP;                    // UPP to our grow zone callback
  55. ModalFilterUPP        gModalFilterUPP;                    // UPP to our custom dialog event filter
  56. UserItemUPP            gUserItemProcUPP;                    // UPP to our custom dialog user item procedure
  57. Handle                gEmergencyMemory;                    // handle to our emergency memory reserve
  58.  
  59. short                 gAppResFile = kInvalidFileRefNum;    // file reference number for this application's resource file
  60. FSSpec                gAppFSSpec;                            // file specification for the application itself
  61. Str255                gAppName;                            // the name of this application
  62.  
  63. long                gMouseClickTime;                    // for double-click calculation
  64. extern OSType         *gValidFileTypes;                    // the list of file types that our application can open
  65.  
  66.  
  67. //////////
  68. //
  69. // main
  70. // The main function for this application.
  71. //
  72. // Set up the application's execution environment; make sure QuickTime (etc.) is installed,
  73. // then start handling events.
  74. //
  75. //////////
  76.  
  77. void main (void)
  78. {
  79.     OSErr        myErr = noErr;
  80.     
  81.     QTFrame_InitMacEnvironment(10L);
  82.     
  83. #if 0    
  84.     // make sure that QuickTime is available and that we can initialize it
  85.     if (!QTUtils_IsQuickTimeInstalled()) {
  86.         QTFrame_ShowWarning("\pQuickTime is not installed on this computer. Exiting.", 0);
  87.         ExitToShell();
  88.     }
  89.  
  90. #if TARGET_CPU_PPC    
  91.     if (!QTUtils_IsQuickTimeCFMInstalled()) {
  92.         QTFrame_ShowWarning("\pThe QuickTime PowerPlug extension is not installed on this computer. Exiting.", 0);
  93.         ExitToShell();
  94.     }
  95. #endif 
  96. #endif
  97.  
  98.     myErr = EnterMovies();
  99.     if (myErr != noErr) {
  100.         QTFrame_ShowWarning("\pCould not initialize QuickTime. Exiting.", myErr);
  101.         ExitToShell();
  102.     }
  103.  
  104.     // do any application-specific initialization
  105.     QTApp_Init(kInitAppPhase_BothPhases);
  106.  
  107.     // get and process events until the user quits
  108.     QTFrame_MainEventLoop();
  109.     
  110.     ExitMovies();
  111.     ExitToShell();
  112. }
  113.  
  114.  
  115. //////////
  116. //
  117. // QTFrame_InitMacEnvironment
  118. // Initialize the Macintosh runtime environment.
  119. //
  120. //////////
  121.  
  122. static void QTFrame_InitMacEnvironment (long theNumMoreMasters)
  123. {
  124. #if TARGET_API_MAC_CARBON
  125. #pragma unused(theNumMoreMasters)
  126. #endif
  127.  
  128.     short            myVRefNum;
  129.     long            myDirID;
  130.  
  131. #if !TARGET_API_MAC_CARBON    
  132.     long            myIndex;
  133.  
  134.     // add more space to the stack
  135.     SetApplLimit((Ptr)(GetApplLimit() - kExtraStackSpaceSize));
  136.             
  137.     // expand heap zone to its limit
  138.     MaxApplZone();
  139.     
  140.     // allocate some additional master pointer blocks
  141.     for (myIndex = 0; myIndex < theNumMoreMasters; myIndex++)
  142.         MoreMasters();
  143.  
  144.     InitGraf(&qd.thePort);
  145.     InitFonts();
  146.     InitWindows();
  147.     InitMenus();
  148.     TEInit();
  149.     InitDialogs(NULL);
  150. #endif
  151.     InitCursor();
  152.  
  153.     // initialize and install the menu bar
  154.     QTFrame_InitMenuBar();
  155.  
  156. #if !TARGET_API_MAC_CARBON
  157.     // install a grow zone procedure to handle low memory situations
  158.     gEmergencyMemory = NewHandle(kEmergencyMemorySize);
  159.     if (gEmergencyMemory != NULL) {
  160.         gAppGrowZoneUPP = NewGrowZoneProc(QTFrame_GrowZoneProcedure);
  161.         SetGrowZone(gAppGrowZoneUPP);
  162.     }
  163. #endif
  164.     
  165.     // initialize foreground/background state
  166.     gAppInForeground = true;
  167.  
  168.     // see whether the new Dialog Manager functions are available
  169. #if TARGET_API_MAC_CARBON
  170.     gHasNewDialogCalls = true;
  171. #else
  172.     gHasNewDialogCalls = QTUtils_TrapAvailable(_DialogDispatch);
  173. #endif
  174.         
  175.     // create modal dialog filter and user item UPPs
  176.     gModalFilterUPP = NewModalFilterProc(QTFrame_StandardModalDialogEventFilter);
  177.     gUserItemProcUPP = NewUserItemProc(QTFrame_StandardUserItemProcedure);
  178.  
  179.     // get the application's resource file
  180.     gAppResFile = CurResFile();
  181.     
  182.     // get the application's name from the resource file
  183.     GetIndString(gAppName, kAppNameResID, kAppNameResIndex);
  184.     
  185.     // get the application's location and save it in gAppFSSpec
  186.     HGetVol(NULL, &myVRefNum, &myDirID);
  187.     FSMakeFSSpec(myVRefNum, myDirID, gAppName, &gAppFSSpec);
  188. }
  189.  
  190.  
  191. //////////
  192. //
  193. // QTFrame_GrowZoneProcedure
  194. // A grow zone procedure. This is straight out of IM: Memory (pp. 1-46ff)
  195. //
  196. //////////
  197.  
  198. PASCAL_RTN long QTFrame_GrowZoneProcedure (Size theBytesNeeded)
  199. {
  200. #pragma unused(theBytesNeeded)
  201.  
  202.     long        myA5;
  203.     Size        myBytesFreed;
  204.     
  205.     // get current A5; we might get called at a time that A5 isn't valid
  206.     myA5 = SetCurrentA5();
  207.     
  208.     if ((*gEmergencyMemory != NULL) && (gEmergencyMemory != GZSaveHnd())) {
  209.         EmptyHandle(gEmergencyMemory);
  210.         myBytesFreed = kEmergencyMemorySize;
  211.     } else {
  212.         myBytesFreed = 0;                        // no more memory to release    
  213.     }    
  214.         
  215.     myA5 = SetA5(myA5);
  216.     
  217.     return(myBytesFreed);
  218. }
  219.  
  220.  
  221. //////////
  222. //
  223. // QTFrame_InitMenuBar
  224. // Set up the menu bar. This is straight out of IM: Macintosh Toolbox Essentials (pp. 3-50ff)
  225. //
  226. //////////
  227.  
  228. static Boolean QTFrame_InitMenuBar (void)
  229. {
  230.     Handle        myMenuBar = NULL;
  231.     long        myResponse;
  232.     OSErr        myErr = noErr;
  233.  
  234.     myMenuBar = GetNewMBar(kMenuBarResID);
  235.  
  236. #if TARGET_API_MAC_CARBON    
  237.     // to get the theme-savvy menu bar, we need to call RegisterAppearanceClient.
  238.     RegisterAppearanceClient();
  239. #endif
  240.  
  241.     if (myMenuBar == NULL)
  242.         return(false);
  243.     
  244.     SetMenuBar(myMenuBar);                                    // install the menus
  245.     DisposeHandle(myMenuBar);
  246.     
  247.     // see whether we are running under MacOS X;
  248.     // if so, remove the Quit menu item and its preceding separator line
  249.     myErr = Gestalt(gestaltSystemVersion, &myResponse);
  250.     if (myErr == noErr)
  251.         if (myResponse >= 0x00000A00) {
  252.             DeleteMenuItem(GetMenuHandle(kFileMenuResID), MENU_ITEM(IDM_EXIT));
  253.             DeleteMenuItem(GetMenuHandle(kFileMenuResID), MENU_ITEM(IDM_EXIT) - 1);    // the separator line
  254.         }
  255.         
  256. #if !TARGET_API_MAC_CARBON    
  257.     AppendResMenu(GetMenuHandle(kAppleMenuResID), 'DRVR');    // add desk accessory names to Apple menu
  258. #endif
  259.     QTFrame_AdjustMenus(NULL, NULL);
  260.     DrawMenuBar();
  261.     
  262.     return(true);
  263. }
  264.  
  265.  
  266. //////////
  267. //
  268. // QTFrame_MainEventLoop
  269. // Retrieve and process events.
  270. //
  271. //////////
  272.  
  273. static void QTFrame_MainEventLoop (void)
  274. {
  275.     EventRecord                myEvent;
  276.     Boolean                    isEventHandled;
  277.     
  278.     while (!gShuttingDown) {
  279. #if !TARGET_API_MAC_CARBON    
  280.         // make sure we've still got our memory reserve; reallocate it if it's been used
  281.         if ((gEmergencyMemory == NULL) || (*gEmergencyMemory == NULL))
  282.             ReallocateHandle(gEmergencyMemory, kEmergencyMemorySize);
  283. #endif
  284.     
  285.         WaitNextEvent(everyEvent, &myEvent, kWNEDefaultSleep, NULL);
  286.         
  287.         // first, perform any application-specific event loop actions
  288.         isEventHandled = QTApp_HandleEvent(&myEvent);
  289.             
  290.         // then, if this event hasn't been handled, let all movie controllers have access to the event
  291.         if (!isEventHandled)
  292.             isEventHandled = CheckMovieControllers(&myEvent);
  293.  
  294.         // then, if this event hasn't been handled, handle it ourselves
  295.         if (!isEventHandled)
  296.             QTFrame_HandleEvent(&myEvent);
  297.         
  298.     } // while (!gShuttingDown)
  299. }
  300.  
  301.  
  302. //////////
  303. //
  304. // QTFrame_MainEventLoop
  305. // Retrieve and process events.
  306. //
  307. //////////
  308.  
  309. void QTFrame_HandleEvent (EventRecord *theEvent)
  310. {
  311.     WindowPtr                myWindow = NULL;
  312.     WindowObject             myWindowObject = NULL;
  313.     short                    myWindowPart;
  314.     Rect                    myScreenRect;
  315.     Rect                    myRefreshArea;
  316.  
  317.     myWindow = FrontWindow();
  318.  
  319.     switch (theEvent->what) {
  320.         case mouseUp:
  321.             gMouseClickTime = TickCount();        // for double-click calculation
  322.             break;
  323.  
  324.         case mouseDown:
  325.         
  326.             myWindowPart = FindWindow(theEvent->where, &myWindow);
  327.  
  328.             // menu bar and window-related events:            
  329.             switch (myWindowPart) {
  330.                 case inSysWindow:
  331. #if !TARGET_API_MAC_CARBON
  332.                     // a mouse click in a window belonging to a desk accessory
  333.                     SystemClick(theEvent, myWindow);
  334. #endif
  335.                     break;
  336.                     
  337.                 case inMenuBar:
  338.                     // a mouse click in the menu bar
  339.                     QTFrame_AdjustMenus(FrontWindow(), NULL);
  340.                     QTFrame_HandleMenuCommand(MenuSelect(theEvent->where));
  341.                     break;
  342.                     
  343.                 case inDrag: {
  344.                     Rect                 myRect;
  345.                     
  346.                     myWindowObject = QTFrame_GetWindowObjectFromWindow(myWindow);
  347.                     if (myWindowObject != NULL) {
  348.                         
  349.                         if ((**myWindowObject).fMovie != NULL)
  350.                             GetMovieBox((**myWindowObject).fMovie, &myRect);
  351.                         
  352.                         if ((**myWindowObject).fGraphicsImporter != NULL)
  353.                             GraphicsImportGetNaturalBounds((**myWindowObject).fGraphicsImporter, &myRect);
  354.                         
  355.                         GetRegionBounds(GetGrayRgn(), &myScreenRect);
  356.                         DragAlignedWindow(myWindow, theEvent->where, &myScreenRect, &myRect, NULL);
  357.  
  358.                     } else {
  359.                         GetRegionBounds(GetGrayRgn(), &myScreenRect);
  360.                         DragWindow(myWindow, theEvent->where, &myScreenRect);
  361.                     }
  362.                     
  363.                     break;                            
  364.                 }
  365.                     
  366.                 case inContent:
  367.                     if (myWindow != FrontWindow()) {
  368.                         SelectWindow(myWindow);
  369.                         MacSetPort((GrafPtr)GetWindowPort(myWindow));
  370.                     } else {
  371.                         QTApp_HandleContentClick(myWindow, theEvent);
  372.                     }
  373.                     
  374.                     break;
  375.                 
  376.                 case inGoAway:
  377.                     if (TrackGoAway(myWindow, theEvent->where)) {
  378.                         // if the option key is down, close all open movie windows; otherwise, close just the frontmost
  379.                         if (theEvent->modifiers & optionKey)
  380.                             QTFrame_CloseMovieWindows();
  381.                         else
  382.                             QTFrame_DestroyMovieWindow(myWindow);
  383.                     }
  384.                     break;
  385.             } // end switch(myWindowPart)
  386.             break;
  387.  
  388.         // system-level events:
  389.         case updateEvt:
  390.             myWindow = (WindowReference)theEvent->message;
  391.             if (myWindow != NULL) {
  392.                 RgnHandle        myVisRegion;
  393.                 
  394.                 // draw an image file
  395.                 myWindowObject = QTFrame_GetWindowObjectFromWindow(myWindow);
  396.                 if (myWindowObject != NULL)
  397.                     if ((**myWindowObject).fGraphicsImporter != NULL)
  398.                         GraphicsImportDraw((**myWindowObject).fGraphicsImporter);
  399.                 
  400.                 myVisRegion = NewRgn();
  401.                 GetPortVisibleRegion(GetWindowPort(myWindow), myVisRegion);
  402.                 GetRegionBounds(myVisRegion, &myRefreshArea);
  403.                 
  404.                 Draw(myWindow, &myRefreshArea);
  405.                 DisposeRgn(myVisRegion);
  406.             }
  407.             break;
  408.             
  409.         case keyDown:
  410.         case autoKey:
  411.             QTFrame_HandleKeyPress(theEvent);
  412.             break;
  413.         
  414.         case diskEvt: {
  415. #if !TARGET_API_MAC_CARBON
  416.             Point            myPoint = {100, 100};
  417.         
  418.             if (HiWord(theEvent->message) != noErr)
  419.                 (void)DIBadMount(myPoint, theEvent->message);
  420. #endif
  421.             break;
  422.         }
  423.         
  424.         case activateEvt:
  425.             myWindow = (WindowReference)theEvent->message;
  426.             
  427.              if (QTFrame_IsAppWindow(myWindow))
  428.                 ActivateController(myWindow, ((theEvent->modifiers & activeFlag) != 0 ));
  429.             break;
  430.             
  431.         case osEvt:
  432.             switch ((theEvent->message >> 24) & 0x00ff) {        // get high byte of message
  433.                 case suspendResumeMessage:
  434.                 
  435.                     // set the foreground/background state
  436.                     gAppInForeground = (theEvent->message & resumeFlag) != 0;
  437.                     
  438.                     // activate the front window, if there is one    
  439.                     if (myWindow != NULL)
  440.                         ActivateController(myWindow, gAppInForeground);
  441.                     break;
  442.                 
  443.                 case mouseMovedMessage:
  444.                     break;
  445.             }
  446.             break;
  447.         
  448.         case kHighLevelEvent:
  449.             AEProcessAppleEvent(theEvent);
  450.             break;
  451.             
  452.         case nullEvent:
  453.             // do idle-time processing for all open movie windows
  454.             myWindow = QTFrame_GetFrontMovieWindow();
  455.             while (myWindow != NULL) {
  456.                 if (gAppInForeground)
  457.                     QTApp_Idle(myWindow);
  458.                     
  459.                 myWindow = QTFrame_GetNextMovieWindow(myWindow);
  460.             }
  461.             break;
  462.     } // switch (theEvent->what)
  463. }
  464.         
  465.  
  466. //////////
  467. //
  468. // QTFrame_HandleMenuCommand
  469. // Handle a menu selection.
  470. //
  471. //////////
  472.  
  473. void QTFrame_HandleMenuCommand (long theMenuResult)
  474. {
  475.     short        myMenuID, myMenuItem;
  476.     Cursor        myArrow;
  477.     
  478.     MacSetCursor(GetQDGlobalsArrow(&myArrow));
  479.  
  480.     myMenuID = HiWord(theMenuResult);
  481.     myMenuItem = LoWord(theMenuResult);
  482.     
  483.     switch (myMenuID) {
  484.     
  485.         case kAppleMenuResID:
  486.             switch (myMenuItem) {
  487.                 case kAboutMenuItem:        // About box
  488.                     QTFrame_ShowAboutBox();     
  489.                     break;
  490.                 
  491.                 default:                     // Apple menu handling
  492. #if !TARGET_API_MAC_CARBON
  493.                     {
  494.                         Str255        myDAName;
  495.                         
  496.                         GetMenuItemText(GetMenuHandle(kAppleMenuResID), myMenuItem, myDAName);
  497.                         (void)OpenDeskAcc(myDAName);
  498.                     }
  499. #endif
  500.                     break;
  501.             }
  502.             break;
  503.  
  504.         case kFileMenuResID:
  505.             QTFrame_HandleFileMenuItem(QTFrame_GetFrontMovieWindow(), MENU_IDENTIFIER(myMenuID, myMenuItem));
  506.             break;
  507.     
  508.         case kEditMenuResID:
  509.             HandleEditMenuItem(QTFrame_GetFrontMovieWindow(), MENU_IDENTIFIER(myMenuID, myMenuItem));
  510.             break;
  511.  
  512.         default:
  513.             // do any application-specific menu handling
  514.             QTApp_HandleMenu(MENU_IDENTIFIER(myMenuID, myMenuItem));
  515.             break;
  516.         
  517.     } // switch (myMenuID)
  518.     
  519.     HiliteMenu(0);
  520. }
  521.  
  522.  
  523. //////////
  524. //
  525. // QTFrame_HandleKeyPress
  526. // Handle key presses. This is modelled on Inside Macintosh: Macintosh Toolbox Essentials, p. 3-78.
  527. //
  528. //////////
  529.  
  530. void QTFrame_HandleKeyPress (EventRecord *theEvent)
  531. {
  532.     char        myKey;
  533.     
  534.     myKey = theEvent->message & charCodeMask;
  535.     
  536.     if (theEvent->modifiers & cmdKey) {
  537.         // if the command key is down, it must be a keyboard shortcut for a menu selection;
  538.         // adjust the menus and find the menu command that the shortcut picks out
  539.         QTFrame_AdjustMenus(FrontWindow(), NULL);
  540.         QTFrame_HandleMenuCommand(MenuKey(myKey));
  541.     } else {
  542.         // otherwise, we'll assume it's meant for our application
  543.         QTApp_HandleKeyPress(myKey);
  544.     }
  545. }
  546.  
  547.  
  548. //////////
  549. //
  550. // QTFrame_QuitFramework
  551. // Do any framework-specific shut-down.
  552. //
  553. //////////
  554.  
  555. void QTFrame_QuitFramework (void)
  556. {
  557.     // set our global flag to indicate we're shutting down
  558.     gShuttingDown = true;
  559.     
  560.     // do application-specific processing that must occur before movie windows are closed
  561.     QTApp_Stop(kStopAppPhase_BeforeDestroyWindows);
  562.     
  563.     // close all open movie windows; note that the user can cancel the shutting down
  564.     QTFrame_CloseMovieWindows();
  565.         
  566.     // test the quit flag; a call to QTFrame_DestroyMovieWindow may have reset it
  567.     if (!gShuttingDown)
  568.         return;
  569.     
  570.     // do application-specific processing that must occur after movie windows are closed
  571.     QTApp_Stop(kStopAppPhase_AfterDestroyWindows);
  572.  
  573.     // release our list of valid file types
  574.     if (gValidFileTypes != NULL)
  575.         DisposePtr((Ptr)gValidFileTypes);
  576.  
  577. #if !TARGET_API_MAC_CARBON    
  578.     // release the grow zone memory
  579.     DisposeHandle(gEmergencyMemory);
  580. #endif
  581.     
  582.     // release any routine descriptors
  583.     DisposeGrowZoneUPP(gAppGrowZoneUPP);
  584.     DisposeModalFilterUPP(gModalFilterUPP);
  585.     DisposeUserItemUPP(gUserItemProcUPP);    
  586. }
  587.  
  588.  
  589. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  590. //
  591. // Framework utilities.
  592. //
  593. // The framework uses the following functions to create movies and handle dialog boxes. You probably won't
  594. // need to use them directly.
  595. //
  596. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  597.  
  598. //////////
  599. //
  600. // QTFrame_CreateMovieWindow
  601. // Create a new window to display the movie in.
  602. //
  603. //////////
  604.  
  605. WindowReference QTFrame_CreateMovieWindow (void)
  606. {
  607.     WindowReference            myWindow = NULL;
  608.     WindowObject            myWindowObject = NULL;
  609.     
  610.     // create a new window to display the movie in
  611.     myWindow = NewCWindow(NULL,
  612.                             &gWindowRect,
  613.                             gWindowTitle,
  614.                             false,
  615.                             noGrowDocProc,
  616.                             (WindowPtr)-1L,
  617.                             true,
  618.                             0);
  619.  
  620.     // create a new window object associated with the new window
  621.     QTFrame_CreateWindowObject(myWindow);
  622.  
  623.     return(myWindow);
  624. }
  625.  
  626.  
  627. //////////
  628. //
  629. // QTFrame_DestroyMovieWindow
  630. // Close the specified movie window.
  631. //
  632. //////////
  633.  
  634. void QTFrame_DestroyMovieWindow (WindowReference theWindow)
  635. {
  636.     WindowObject        myWindowObject = NULL;
  637.     OSErr                myErr = noErr;
  638.     
  639.     // get the window object associated with the specified window
  640.     myWindowObject = QTFrame_GetWindowObjectFromWindow(theWindow);
  641.     if (myWindowObject == NULL) {
  642.         // if the window passed in isn't a movie window, just dispose of it and return
  643.         if (theWindow != NULL) {
  644.             DisposeWindow(theWindow);
  645.             theWindow = NULL;
  646.         }
  647.         return;
  648.     }
  649.     
  650.     // if the window's data is "dirty", give the user a chance to save it
  651.     if ((**myWindowObject).fIsDirty) {
  652.         Str255                        myString;
  653.         NavAskSaveChangesAction        myAction;
  654.         NavAskSaveChangesResult        myResult;
  655.         NavDialogOptions            myDialogOptions;
  656.         NavEventUPP                    myEventUPP = NewNavEventProc(QTFrame_HandleNavEvent);
  657.  
  658.         // get the title of the window
  659.         GetWTitle(theWindow, myString);
  660.         
  661.         // install the application and document names
  662.         NavGetDefaultDialogOptions(&myDialogOptions);
  663.         BlockMoveData(gAppName, myDialogOptions.clientName, gAppName[0] + 1);
  664.         BlockMoveData(myString, myDialogOptions.savedFileName, myString[0] + 1);
  665.         
  666.         // specify the action
  667.         myAction = gShuttingDown ? kNavSaveChangesQuittingApplication : kNavSaveChangesClosingDocument;
  668.         
  669.         // display the "Save changes" dialog box
  670.         myErr = NavAskSaveChanges(&myDialogOptions, myAction, &myResult, myEventUPP, NULL);
  671.         if (myErr != noErr)
  672.             myResult = kNavAskSaveChangesCancel;
  673.             
  674.         switch (myResult) {
  675.             case kNavAskSaveChangesSave:
  676.                 // save the data in the window
  677.                 QTFrame_UpdateMovieFile(theWindow);
  678.                 break;
  679.                 
  680.             case kNavAskSaveChangesCancel:
  681.                 // do not close the window, and do not quit the application
  682.                 gShuttingDown = false;
  683.                 return;
  684.                 
  685.             case kNavAskSaveChangesDontSave:
  686.                 // discard any unsaved changes (that is, don't do anything)
  687.                 break;
  688.         }
  689.  
  690.         DisposeNavEventUPP(myEventUPP);
  691.     }
  692.  
  693.     // if we got to this point, it's okay to close and destroy the window
  694.     QTFrame_CloseWindowObject(myWindowObject);
  695.  
  696.     DisposeWindow(theWindow);
  697. }
  698.  
  699.  
  700. //////////
  701. //
  702. // QTFrame_StandardUserItemProcedure
  703. // A standard user-item procedure to outline the OK button in a modal dialog.
  704. //
  705. //////////
  706.  
  707. PASCAL_RTN void QTFrame_StandardUserItemProcedure (DialogPtr theDialog, short theItem)
  708. {
  709. #pragma unused(theItem)
  710.  
  711.     short                myItemKind;            // for GetDialogItem
  712.     Handle                myItemHandle;        // for GetDialogItem
  713.     Rect                myItemRect;            // for GetDialogItem
  714.  
  715.     if (!gHasNewDialogCalls) {        // no need to do any of this if the new Dialog Manager calls are available
  716.         GetDialogItem(theDialog, kStdOkItemIndex, &myItemKind, &myItemHandle, &myItemRect);        
  717.         MacInsetRect(&myItemRect, -4, -4);
  718.         PenSize(3, 3);
  719.         FrameRoundRect(&myItemRect, 16, 16);
  720.         PenSize(1, 1);
  721.     }
  722. }
  723.  
  724.  
  725. //////////
  726. //
  727. // QTFrame_StandardModalDialogEventFilter
  728. // A standard modal dialog event filter. 
  729. //
  730. //////////
  731.  
  732. PASCAL_RTN Boolean QTFrame_StandardModalDialogEventFilter (DialogPtr theDialog, EventRecord *theEvent, short *theItemHit)
  733. {
  734.     Boolean                myEventHandled = false;
  735.     short                myItemKind;            // for GetDialogItem
  736.     Handle                myItemHandle;        // for GetDialogItem
  737.     Rect                myItemRect;            // for GetDialogItem
  738.     unsigned long        myTicks;            // for Delay
  739.     char                myKey;        
  740.     WindowReference        myWindow = NULL;
  741.     short                myPart;    
  742.     OSErr                myErr = noErr;
  743.         
  744.     switch (theEvent->what) {
  745.         case updateEvt:
  746.             // update the specified window, if it's behind the modal dialog box
  747.             myWindow = (WindowReference)theEvent->message;
  748.             if ((myWindow != NULL) && (myWindow != GetDialogWindow(theDialog))) {
  749.                 QTFrame_HandleEvent(theEvent);
  750.                 myEventHandled = false;        // so sayeth IM
  751.             }
  752.             break;
  753.  
  754.         case nullEvent:
  755.             // do idle-time processing for all open windows in our window list
  756.             if (gAppInForeground) 
  757.                 QTFrame_IdleMovieWindows();
  758.  
  759.             myEventHandled = false;
  760.             break;
  761.             
  762.         case keyDown:
  763.         case autoKey:
  764.             // if new Dialog Manager calls are NOT available, handle certain key presses
  765.             if (!gHasNewDialogCalls) {
  766.                 // first, map Command-period to Escape key...
  767.                 myKey = theEvent->message & charCodeMask;
  768.                 if (theEvent->modifiers & cmdKey)
  769.                     if (myKey == kPeriod)
  770.                         myKey = kEscapeKey;
  771.                         
  772.                 // ...then, handle the standard keyboard equivalents of OK and Cancel buttons
  773.                 switch (myKey) {
  774.                     case kReturnKey:
  775.                     case kEnterKey:
  776.                         *theItemHit = kStdOkItemIndex;
  777.                         GetDialogItem(theDialog, kStdOkItemIndex, &myItemKind, &myItemHandle, &myItemRect);
  778.                         HiliteControl((ControlHandle)myItemHandle, kControlButtonPart);
  779.                         Delay(kMyButtonDelay, &myTicks);
  780.                         HiliteControl((ControlHandle)myItemHandle, kControlNoPart);
  781.                         myEventHandled = true;
  782.                         break;
  783.                     case kEscapeKey:
  784.                         *theItemHit = kStdCancelItemIndex;
  785.                         GetDialogItem(theDialog, kStdCancelItemIndex, &myItemKind, &myItemHandle, &myItemRect);
  786.                         HiliteControl((ControlHandle)myItemHandle, kControlButtonPart);
  787.                         Delay(kMyButtonDelay, &myTicks);
  788.                         HiliteControl((ControlHandle)myItemHandle, kControlNoPart);
  789.                         myEventHandled = true;
  790.                         break;
  791.                     default:
  792.                         break;
  793.                 }
  794.             }
  795.             break;
  796.             
  797.         case mouseDown:
  798.             myPart = FindWindow(theEvent->where, &myWindow);
  799.             if ((myPart == inDrag) && (myWindow == GetDialogWindow(theDialog))) {
  800.                 Rect        myScreenRect;
  801.                 
  802.                 GetRegionBounds(GetGrayRgn(), &myScreenRect);
  803.                 DragWindow(myWindow, theEvent->where, &myScreenRect);
  804.                 myEventHandled = true;
  805.             }
  806.             break;
  807.             
  808.         default:
  809.             myEventHandled = false;
  810.             break;
  811.     }    
  812.     
  813.     // let the OS's standard filter proc handle the event, if it hasn't already been handled
  814.     if (gHasNewDialogCalls && (myEventHandled == false))
  815.         myEventHandled = StdFilterProc(theDialog, theEvent, theItemHit);
  816.     
  817.     return(myEventHandled);
  818. }
  819.  
  820.  
  821. //////////
  822. //
  823. // QTFrame_ShowAboutBox
  824. // Display and manage the About dialog box.
  825. //
  826. //////////
  827.  
  828. void QTFrame_ShowAboutBox (void)
  829. {
  830.     DialogPtr            myDialog = NULL;
  831.     short                 myItem;
  832.     short                 mySavedResFile;
  833.     GrafPtr                mySavedPort;
  834.     short                myItemKind;
  835.     Handle                myItemHandle;
  836.     Rect                myItemRect;
  837.     
  838.     // get the current resource file and port
  839.     mySavedResFile = CurResFile();
  840.     GetPort(&mySavedPort);
  841.     
  842.     // set the application's resource file;
  843.     // otherwise, we'd get the dialog's resources from the current resource file,
  844.     // which might not be the correct one....
  845.     UseResFile(gAppResFile);
  846.     
  847.     // deactivate any frontmost movie window
  848.     ActivateController(QTFrame_GetFrontMovieWindow(), false);
  849.     
  850.     myDialog = GetNewDialog(kAboutBoxID, NULL, (WindowPtr)-1L);
  851.     if (myDialog == NULL)
  852.         goto bail;
  853.         
  854.     SetPortDialogPort(myDialog);
  855.         
  856.     if (gHasNewDialogCalls)
  857.         SetDialogDefaultItem(myDialog, kStdOkItemIndex);
  858.     
  859.     // make sure that the OK button is outlined in bold, even if new Dialog Manager calls not available
  860.     GetDialogItem(myDialog, kOKButtonUserItem, &myItemKind, &myItemHandle, &myItemRect);
  861.     SetDialogItem(myDialog, kOKButtonUserItem, myItemKind, (Handle)gUserItemProcUPP, &myItemRect);
  862.  
  863.     // display and handle events in the dialog box until the user clicks OK
  864.     do {
  865.         ModalDialog(gModalFilterUPP, &myItem);
  866.     } while (myItem != kStdOkItemIndex);
  867.     
  868. bail:
  869.     // restore the previous resource file and port
  870.     MacSetPort(mySavedPort);
  871.     UseResFile(mySavedResFile);
  872.     
  873.     if (myDialog != NULL)
  874.         DisposeDialog(myDialog);
  875. }
  876.  
  877.  
  878. //////////
  879. //
  880. // QTFrame_ShowWarning
  881. // Display a warning box.
  882. //
  883. //////////
  884.  
  885. void QTFrame_ShowWarning (Str255 theMessage, OSErr theErr)
  886. {
  887.     Str255                myString;
  888.     short                 mySavedResFile;
  889.     
  890.     // get the current resource file and set the application's resource file
  891.     mySavedResFile = CurResFile();
  892.     UseResFile(gAppResFile);
  893.  
  894.     // insert argument into the message text template, to get the message text
  895.     NumToString(theErr, myString);
  896.     ParamText("\pWarning!", theMessage, theErr ? myString: NULL, NULL);
  897.  
  898.     // display the dialog box
  899.     Alert(kAlertErrorID, gModalFilterUPP);
  900.     
  901.     // restore the original resource file
  902.     UseResFile(mySavedResFile);
  903. }
  904.  
  905.